#include "line.h"
#include "util.h" // fdist

using namespace Underlight;

#include "room.h"
#include "flags.h"
#include "level.h"
#include "sector.h"

void
ToggleFlag (int& flags, int flag)
{
  if (flags & flag)
    flags &= ~flag;
  else
    flags |= flag;
}

Line::Line ( const FileLinedef* pLine,
             const Level*       level,
             bool               line_in_sector,
             VertexData         to_,
             VertexData         from_,
             int                id )
{
  num = id;

  to.x = to_.x;
  to.y = to_.y;

  from.x = from_.x;
  from.y = from_.y;

  from_idx = pLine->from;
  to_idx   = pLine->to;

  num_ceil_walls  = 0;
  num_floor_walls = 0;

  Room* room = level->RoomFromSector (pLine->sector);

  sector       = room->GetSector (pLine->sector);
  facingsector = room->GetSector (pLine->facingsector);

  fwall_bitmap  = pLine->fwall_bitmap;
  animation_end = pLine->animation_end;
  cwall_bitmap  = pLine->cwall_bitmap;

  fwall_u_offset = (float)pLine->fwall_u_offset;
  fwall_v_offset = (float)pLine->fwall_v_offset;

  cwall_u_offset = (float)pLine->cwall_u_offset;
  cwall_v_offset = (float)pLine->cwall_v_offset;

  flags = pLine->flags;

  // If texture is to be stretched/compressed, offsets are not used
  if (flags & LINE_STRETCH_FWALL_HORZ)
    fwall_u_offset = 0;

  if (flags & LINE_STRETCH_FWALL_VERT)
    fwall_v_offset = 0;

  if (flags & LINE_STRETCH_CWALL_HORZ)
    cwall_u_offset = 0;

  if (flags & LINE_STRETCH_CWALL_VERT)
    cwall_v_offset = 0;

  bool  floor_base   = (flags & LINE_SECTOR_FLOOR_BASE);
  bool  ceiling_base = (flags & LINE_SECTOR_CEILING_BASE);

  if (line_in_sector == false) // line is in facing sector
  {
    generated = true;

    if (room->GetSector (pLine->facingsector)) {
      // swap vertices, and sectors;
      from_idx = pLine->to;
      to_idx   = pLine->from;

      from.x = to_.x;
      from.y = to_.y;

      to.x = from_.x;
      to.y = from_.y;

      sector       = room->GetSector (pLine->facingsector);
      facingsector = room->GetSector (pLine->sector);

      extern void DumpLineFlags (const int& iFlags);
      //DumpLineFlags (pLine->flags);

      //flags = pLine->flags;
      //DumpLineFlags (pLine->flags);

      // set base booleans
      floor_base   = (flags & LINE_FACING_FLOOR_BASE );
      ceiling_base = (flags & LINE_FACING_CEILING_BASE);
    } else {
////      eTB_Printf ("Hmm\n");
    }
  } else {
    generated = false;
  }

  // Important: Don't allow 0 length, otherwise COS and COSINE will
  //            divide by zero.
  //
  //            While the SINE and COSINE are not integers as they were
  //            in the original Underlight code, division by zero will
  //            still give undesired results.
  length = fdist (x1 (), y1 (), x2 (), y2 ());

  if (length == 0.0f)
    length = 0.000001f; // Avoid lines with 0 length

  // Set the Sine and Cosine of the line
  COS  = (x2 () - x1 ()) / length;
  SINE = (y2 () - y1 ()) / length;

  if (floor_base) {
    if (! sector->floor)
      sector->floor = new Surface (sector->floor_height, 0.0f, (sector->flags & SECTOR_NO_STRETCH_FLOOR));
    sector->floor->set_baseline (this);
  }

  if (ceiling_base) {
    if (! sector->ceil)
      sector->ceil = new Surface (sector->ceiling_height, 0.0f, (sector->flags & SECTOR_NO_STRETCH_CEILING));
    sector->ceil->set_baseline (this);
  }

  Line* firstline   = sector->firstline; // save first line
  sector->firstline = this;              // add line to beggining of linked list
  this->nextline    = firstline;         // link up rest of list to linea

  /* These will be built by sector... */
  fwall = NULL;
  cwall = NULL;
}

bool
Line::IsTripLine (void) const
{
  return false;
}


TripLine::TripLine ( const FileLinedef* pLine,
                     const Level*       level,
                     bool               line_in_sector,
                     VertexData         to_,
                     VertexData         from_,
                     int                id ) :
Line (pLine, level, line_in_sector, to_, from_, id)
{
  trip_flags = pLine->TripFlags;

  if (pLine->TripFlags & TRIP_TELEPORT)
    action = Teleport;
  if (pLine->TripFlags & TRIP_GOALPOSTING)
    action = GoalPost;
  if (pLine->TripFlags & TRIP_LEVELCHANGE)
    action = LevelChange;
  if (pLine->TripFlags & TRIP_SOUNDEFFECT)
    action = SoundEffect;
  if (pLine->TripFlags & TRIP_SHOWMESSAGE)
    action = ShowMessage;
  if (pLine->TripFlags & TRIP_QUESTBUILDER)
    action = QuestBuild;

  event = 0;

  if (pLine->flags & TRIP_CROSS)
    event |= Cross;
  if (pLine->flags & TRIP_ACTIVATE)
    event |= Activate;

  trip1 = pLine->trip1;
  trip2 = pLine->trip2;
  trip3 = pLine->trip3;
  trip4 = pLine->trip4;

//#define DUMP_TRIP_LINES
#ifdef  DUMP_TRIP_LINES
  // ids < 0 are just duplicate lines with opposite
  //   windings... do not bother listing them.
  if (event & Cross && id >= 0) {
    DumpLine (this);
  }
#endif
}

bool
TripLine::IsTripLine (void) const
{
  return true;
}


Line*
Underlight::CreateLine ( const FileLinedef* pLine,
                         const Level*       level,
                         bool               in_sector,
                         VertexData         v1,
                         VertexData         v2,
                         Line*              original,
                         int                id )
{
  Line* line = NULL;

  if ((pLine->flags & TRIP_CROSS) ||
      (pLine->flags & TRIP_ACTIVATE))
  {
    line = new TripLine (pLine, level, in_sector, v1, v2, id);
  } else {
    line = new Line     (pLine, level, in_sector, v1, v2, id);
  }

  line->original_line = original;

  return line;
}
